import Foundation
import UIKit

public enum LogLevel: Int {
    case debug = 0
    case info = 1
    case warning = 2
    case error = 3
    
    var emoji: String {
        switch self {
        case .debug: return "🔍"
        case .info: return "ℹ️"
        case .warning: return "⚠️"
        case .error: return "❌"
        }
    }
    
    var prefix: String {
        switch self {
        case .debug: return "DEBUG"
        case .info: return "INFO"
        case .warning: return "WARNING"
        case .error: return "ERROR"
        }
    }
}

public class MarkdownLogger {
    public static let shared = MarkdownLogger()
    
    private init() {
        // 在初始化时创建日志文件
        createNewLogFile()
    }
    
    // MARK: - Configuration
    
    public var minimumLogLevel: LogLevel = .debug {
        didSet {
            info("Log level changed to: \(minimumLogLevel.prefix)")
        }
    }
    
    public var isEnabled: Bool = true {
        didSet {
            if isEnabled {
                info("Logging enabled")
            } else {
                info("Logging disabled")
            }
        }
    }
    
    public var shouldLogToFile: Bool = false {
        didSet {
            info("File logging \(shouldLogToFile ? "enabled" : "disabled")")
        }
    }
    
    public var logFileURL: URL? {
        didSet {
            if let url = logFileURL {
                info("Log file set to: \(url.path)")
            }
        }
    }
    
    public var maxLogFileSize: Int = 10 * 1024 * 1024 // 10MB
    public var maxLogFiles: Int = 5
    
    // MARK: - Private Properties
    
    private let dateFormatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS"
        return formatter
    }()
    
    private let queue = DispatchQueue(label: "com.markdownuikit.logger", qos: .utility)
    private let fileManager = FileManager.default
    
    // MARK: - Logging Methods
    
    public func debug(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
        log(message, level: .debug, file: file, function: function, line: line)
    }
    
    public func info(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
        log(message, level: .info, file: file, function: function, line: line)
    }
    
    public func warning(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
        log(message, level: .warning, file: file, function: function, line: line)
    }
    
    public func error(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
        log(message, level: .error, file: file, function: function, line: line)
    }
    
    public func error(_ error: Error, file: String = #file, function: String = #function, line: Int = #line) {
        log("Error: \(error.localizedDescription)", level: .error, file: file, function: function, line: line)
        if let nsError = error as? NSError {
            log("Domain: \(nsError.domain), Code: \(nsError.code)", level: .error, file: file, function: function, line: line)
            if let reason = nsError.localizedFailureReason {
                log("Reason: \(reason)", level: .error, file: file, function: function, line: line)
            }
            if let suggestion = nsError.localizedRecoverySuggestion {
                log("Suggestion: \(suggestion)", level: .error, file: file, function: function, line: line)
            }
        }
    }
    
    // MARK: - Private Methods
    
    private func log(_ message: String, level: LogLevel, file: String, function: String, line: Int) {
        guard isEnabled, level.rawValue >= minimumLogLevel.rawValue else { return }
        
        let timestamp = dateFormatter.string(from: Date())
        let fileName = (file as NSString).lastPathComponent
        let threadName = Thread.current.isMainThread ? "main" : Thread.current.name ?? "background"
        
        let logMessage = """
        \(timestamp) \(level.emoji) [\(level.prefix)][\(threadName)][\(fileName):\(line)] \(function)
        Message: \(message)
        
        """
        
        queue.async { [weak self] in
            print(logMessage)
            
            if self?.shouldLogToFile == true {
                self?.writeToFile(logMessage)
            }
        }
    }
    
    private func writeToFile(_ message: String) {
        guard let logFileURL = logFileURL else { return }
        
        do {
            let logMessage = message + "\n"
            if fileManager.fileExists(atPath: logFileURL.path) {
                let attributes = try fileManager.attributesOfItem(atPath: logFileURL.path)
                let fileSize = attributes[.size] as? Int ?? 0
                
                if fileSize > maxLogFileSize {
                    rotateLogFiles()
                    try logMessage.write(to: logFileURL, atomically: true, encoding: .utf8)
                } else {
                    let fileHandle = try FileHandle(forWritingTo: logFileURL)
                    defer { fileHandle.closeFile() }
                    fileHandle.seekToEndOfFile()
                    if let data = logMessage.data(using: .utf8) {
                        fileHandle.write(data)
                    }
                }
            } else {
                try logMessage.write(to: logFileURL, atomically: true, encoding: .utf8)
            }
        } catch {
            print("Failed to write to log file: \(error)")
        }
    }
    
    // MARK: - Log File Management
    
    public func createNewLogFile() {
        let documentsPath = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
        let logsDirectory = documentsPath.appendingPathComponent("MarkdownLogs")
        
        do {
            if !fileManager.fileExists(atPath: logsDirectory.path) {
                try fileManager.createDirectory(at: logsDirectory, withIntermediateDirectories: true)
            }
            
            let timestamp = dateFormatter.string(from: Date()).replacingOccurrences(of: ":", with: "-")
            logFileURL = logsDirectory.appendingPathComponent("markdown_log_\(timestamp).log")
            
            info("Created new log file: \(logFileURL?.path ?? "unknown")")
        } catch {
            print("Failed to create logs directory: \(error)")
        }
    }
    
    private func rotateLogFiles() {
        guard let logFileURL = logFileURL else { return }
        let logsDirectory = logFileURL.deletingLastPathComponent()
        
        do {
            let logFiles = try fileManager.contentsOfDirectory(at: logsDirectory,
                                                             includingPropertiesForKeys: [.creationDateKey],
                                                             options: [.skipsHiddenFiles])
                .filter { $0.pathExtension == "log" }
                .sorted { file1, file2 in
                    let date1 = try? file1.resourceValues(forKeys: [.creationDateKey]).creationDate ?? Date.distantPast
                    let date2 = try? file2.resourceValues(forKeys: [.creationDateKey]).creationDate ?? Date.distantPast
                    return date1! > date2!
                }
            
            // 删除多余的日志文件
            if logFiles.count > maxLogFiles {
                for file in logFiles[maxLogFiles...] {
                    try fileManager.removeItem(at: file)
                    info("Deleted old log file: \(file.path)")
                }
            }
        } catch {
            print("Failed to rotate log files: \(error)")
        }
    }
    
    public func clearLogs() {
        guard let logFileURL = logFileURL else { return }
        let logsDirectory = logFileURL.deletingLastPathComponent()
        
        do {
            let logFiles = try fileManager.contentsOfDirectory(at: logsDirectory,
                                                             includingPropertiesForKeys: nil,
                                                             options: [.skipsHiddenFiles])
                .filter { $0.pathExtension == "log" }
            
            for file in logFiles {
                try fileManager.removeItem(at: file)
            }
            
            info("Cleared all log files")
            createNewLogFile()
        } catch {
            print("Failed to clear logs: \(error)")
        }
    }
    
    public func getLogFileContents() -> String? {
        guard let logFileURL = logFileURL else { return nil }
        return try? String(contentsOf: logFileURL, encoding: .utf8)
    }
    
    public func exportLogs() -> [URL] {
        guard let logFileURL = logFileURL else { return [] }
        let logsDirectory = logFileURL.deletingLastPathComponent()
        
        do {
            return try fileManager.contentsOfDirectory(at: logsDirectory,
                                                     includingPropertiesForKeys: nil,
                                                     options: [.skipsHiddenFiles])
                .filter { $0.pathExtension == "log" }
        } catch {
            print("Failed to export logs: \(error)")
            return []
        }
    }
} 
